package br.com.felix.dbm.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JPanel;

import br.com.felix.dbm.controller.ColumnController;
import br.com.felix.dbm.controller.DataModelController;
import br.com.felix.dbm.controller.TableController;
import br.com.felix.dbm.controller.TableControllerSet;
import br.com.felix.dbm.database.Column;
import br.com.felix.dbm.database.Table;
import br.com.felix.dbm.log.Logger;
import br.com.felix.dbm.ui.layout.EditorLayout;
import br.com.felix.dbm.ui.layout.EditorListener;

/**
 * Canvas for the database modeling.
 * */
public class EditorCanvas extends JPanel implements EditorSideBarDelegate {

	private static final long serialVersionUID = -3206037248094356078L;

	private static Logger logger = Logger.getLogger(EditorCanvas.class);

	private EditorLayout mgr;
	private List<EditorListener> listeners = new ArrayList<EditorListener>();
	private EditorUi parent;
	private DataModelController dmc;
	private Map<Table,TableUi> mapViews = new HashMap<Table,TableUi>();
	
	
	public EditorCanvas(EditorLayout mgr) {
		this.mgr = mgr;
		configureDefaults();
	}



	private void configureDefaults() {
		removeAll();
		setLayout(mgr);
		setBackground(Color.LIGHT_GRAY);
	}



	public void addTable(final TableController tableController, boolean isNew) {
		Object constraints = mgr.addTable(tableController, isNew);
		TableUi tableView = tableController.getView();
		tableView.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				fireTableSelectedEvent(tableController);
			}
		});
		mapViews.put(tableController.getModel(), tableView);
		add(tableView, constraints);
		validate();
		if(getParent()!=null){
			getParent().validate();
		}
	}



	private void fireTableSelectedEvent(TableController tableController) {
		logger.debug("Event Fired!!!");
		for (EditorListener el : listeners) {
			el.tableSelected(tableController);
		}
	}



	public void setDataModelController(DataModelController dmc) {
		mgr.setDataModelController(dmc);
		this.dmc = dmc;
	}



	public void addEditorListener(EditorListener listener) {
		listeners.add(listener);
	}



	public void setParent(EditorUi parent) {
		this.parent = parent;
	}
	
	
	public void clear(){
		mgr.clear();
		logger.debug("Removing all components.");
		removeAll();
		validate();
	}



	@Override
	public void paint(Graphics g) {
		super.paint(g);
		List<Table> tables = dmc.getDataModel().getTables();
		ColumnController cc;
		ColumnUi columnUiTo, columnUiFrom;
		for(Table table: tables){
			for(Column fk: table.getForeignKeys()){
				cc = ColumnController.getInstance(fk);
				TableController tableController = dmc.getTableControllerOf(table);
				if(tableController==null){
					logger.error("Could not find TableController of table " + table.toString(), new NullPointerException());
				}
				else{
					TableUi tableUiFrom = tableController.getView();
					columnUiFrom = cc.getViewForTable(tableUiFrom);
					TableUi tableUiTo = dmc.getTableControllerOf(fk.getTable()).getView();
					columnUiTo = cc.getViewForTable(tableUiTo);
					if(columnUiFrom != null && columnUiTo != null){
						logger.debug("ColumnUi from",columnUiFrom.toString());
						logger.debug("ColumnUi to",columnUiTo.toString());
						if(columnUiFrom.isShowing() && columnUiTo.isShowing()){
							drawLine((Graphics2D)g,tableUiFrom.getBounds(),tableUiTo.getBounds(),columnUiFrom.getBounds(),columnUiTo.getBounds());
						}
					}
					else{
						logger.debug("columnFrom is null ="+(columnUiFrom==null));
						logger.debug("columnTo is null ="+(columnUiTo==null));
					}
				}
			}
		}
	}



	private void drawLine(Graphics2D g,Rectangle fromParent, Rectangle toParent, Rectangle from, Rectangle to) {
		g.setColor(Color.blue);
		int border = Style.getTableBorder();
		int xFrom = border + fromParent.x + from.x;
		int yFrom = border + fromParent.y+ from.y + from.height / 2;
		int xTo = border + toParent.x+ to.x;
		int yTo = border + toParent.y + to.y + to.height / 2;
		logger.debug("xF="+xFrom+",yF="+yFrom+"; xTo="+xTo+",yTo="+yTo);
		g.drawLine(xFrom, yFrom, xTo, yTo);
		g.drawLine(xFrom+1, yFrom+1, xTo+1, yTo+1);
	}



	private void removeAll(TableControllerSet affectedTables) {
		for(TableController tc: affectedTables){
			TableUi tableUi = mapViews.get(tc.getModel());
			remove(tableUi);
			mapViews.remove(tc.getModel());
		}
		getParent().validate();
		repaint();
	}



	public void setCentralTable(Table model) {
		mgr.setCentralTable(model);
	}



	public void selectTable(TableController source) {
		TableControllerSet relatedTables = source.getColumnControllers().foreignKeysOfTable(source.getModel()).getTableControllerSet();
		dmc.removeAll(relatedTables);
		removeAll(relatedTables);
		mgr.selectTable(source);
		layoutTables(relatedTables);
	}
	
	
	private void layoutTables(TableControllerSet affectedTables) {
		for(TableController tc:affectedTables){
			dmc.addTableController(tc);
			addTable(tc, false);
		}
		dmc.updateTableViews();
		if(getParent()!=null){
			getParent().validate();
		}
	}



	@Override
	public void tableNeighborsSelected(Table table) {
		TableController tc = dmc.getTableControllerOf(table);
		if(tc!=null){
			TableControllerSet relatedTables = tc.getColumnControllers().foreignKeysOfTable(table).getTableControllerSet();
			TableUi tableUi;
			for(TableController tctrl:relatedTables){
				tableUi = tctrl.getView();
				tableUi.setVisible(!tableUi.isVisible());
			}
		}
	}



	@Override
	public void tableSelected(Table table, boolean selected) {
		TableController tc = dmc.getTableControllerOf(table);
		if(tc!=null){
			TableUi tableUi = tc.getView();
			tableUi.setVisible(selected);
		}
	}

	
}
